/**
 * Copyright 1996 self.com.au
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License. (http://www.apache.org/licenses/LICENSE-2.0)
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed 
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for 
 * the specific language governing permissions and limitations under the License.
 *
 * <dhamma-message src="Atisha (11th century Tibetan Buddhist master)">
 * 	The greatest achievement is selflessness. The greatest worth is self-mastery.
 * 	The greatest quality is seeking to serve others. The greatest precept is continual awareness.
 * 	The greatest medicine is the emptiness of everything. The greatest action is not conforming with the worlds ways.
 * 	The greatest magic is transmuting the passions. The greatest generosity is non-attachment.
 * 	The greatest goodness is a peaceful mind. The greatest patience is humility.
 * 	The greatest effort is not concerned with results. The greatest meditation is a mind that lets go.
 * 	The greatest wisdom is seeing through appearances. 
 * </dhamma-message>
 *
 * @author Ashin Wimalajeewa
 *
 * Note, this is a very old runtime library that I have evolved since 1996. I rarely use it
 * now because the Apache Commons project has made it obsolete.
 */
package self.io;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import self.lang.StringUtils;

final public class PathUtils {
	
	private PathUtils() {
    	// nothing to do.
	}

	static public String toRelativePath(String fullyQualBaseLoc,
			String fullyQualCurrentLoc) {
		return getRelativePath(fullyQualBaseLoc, fullyQualCurrentLoc, '/');
	}

	static public String toFullyQualified(String currLoc, String relativeLoc)
			throws IllegalArgumentException {
		if ((currLoc == null) || (relativeLoc == null))
			throw new IllegalArgumentException("non-null arguments required");
		try {
			if (relativeLoc.startsWith("/")) {
				while (relativeLoc.startsWith("/../"))
					relativeLoc = relativeLoc.substring(3);
				return relativeLoc;
			}

			String assembly = "/" + relativeLoc;
			assembly = StringUtils.replace(assembly, "//", "/");
			assembly = currLoc + assembly;
			assembly = StringUtils.replace(assembly, "//", "/");
			File tmp = new File(assembly);
			File tmp1 = tmp.getCanonicalFile();
			String ret = tmp1.getAbsolutePath();
			if (File.separatorChar == '\\') {
				ret = ret.substring(2);
				ret = StringUtils.replace(ret, "\\", "/");
			}
			return ret;
		} catch (IOException err) {
			throw new IllegalArgumentException("err.converting.canonical.file");
		}
	}

	static public String toName(String fullyQualifiedPath) {
		File fetchName = new File(fullyQualifiedPath);
		return fetchName.getName();
	}
	
	static public String toFileExtention(String fileName) {
		String ret = "";
		int pos = fileName.lastIndexOf('.');
		if (pos > -1 && pos < fileName.length()-1)
			ret = fileName.substring(pos + 1);
		return ret;
	}

	static public String toParentPath(String fullyQualifiedPath) {
		if (fullyQualifiedPath.equals("/"))
			return fullyQualifiedPath;
		File fetchParent = new File(fullyQualifiedPath);
		String ret = fetchParent.getParent();
		// asw added 17/04/05 when sending a path without any directory
		// qualification
		if (ret == null)
			return "/";
		ret = StringUtils.replace(ret, "\\", "/");
		return ret;
	}

	static public String makePathEndWithSlash(String path) {
		if (path.endsWith("/"))
			return path;
		return path + "/";
	}

	static public String makePathStartWithSlash(String path) {
		if (path.startsWith("/"))
			return path;
		return "/" + path;
	}

	static public String removePathEndWithSlash(String path) {
		int len = path.length();
		if (path.endsWith("/") && len > 1)
			path = path.substring(0, len - 1);
		return path;
	}

	static String[][] data = {
			{"/test/hello/", "/test/man/test.doc"},
			{"/test/hello", "/test/man/test.doc"},
			{"/test/hello-1/", "/test/hello-2/test.doc"},
			{"/t/h/", "/t/h"},
			{"/t/h/", "/t/h/"},
			{"/t/h/", "/t/h/test.doc"},
			{"/t/h/", "/1/h"},
			{"/t/h/", "/1/h/test.doc"},
			{"/self/aid/collaborative", "/self/aid/collaborative/Benefits"},
			{"/ape/region/fsat/adm/edc/methodology/20-40/",
					"/ape/region/fsat/adm/edc/methodology/"},
			{"/ape/region/fsat/adm/edc/methodology/20-40/",
					"/ape/region/fsat/adm/edc/methodology/Index"},
			{"/ape/region/fsat/adm/edc/methodology/20-40/happy/",
					"/ape/region/fsat/adm/edc/methodology/"},
			{"/ape/region/fsat/adm/edc/methodology/20-40/happy/",
					"/ape/region/fsat/adm/edc/methodology/Index"},
			{
					"/perspectives/project/cbib/foundation/development/UserInterface/cookbook/",
					"/perspectives/project/cbib/foundation/development/UserInterface.wik"},
			{"/usr/ash/wiki/", "/"}};

	static public void main(String[] args) {
		int max = data.length;

		for (int cntr = 0; cntr < max; cntr++) {
			String base = data[cntr][0];
			String curr = data[cntr][1];

//			String rel = toRelative(base, curr, '/');
			String rel = getRelativePath(base, curr, '/');
			System.out.println("base, curr, rel->" + base + "\t" + curr + "\t"
					+ rel);
		}
	}

	/**
	 * break a path down into individual elements and add to a list. example :
	 * if a path is /a/b/c/d.txt, the breakdown will be [d.txt,c,b,a]
	 * 
	 * @param f
	 *            input file
	 * @return a List collection with the individual elements of the path in
	 *         reverse order
	 */
	private static List getPathList(File f) {
		List l = new ArrayList();
		File r;
		try {
			r = f.getCanonicalFile();
			while (r != null) {
				l.add(r.getName());
				r = r.getParentFile();
			}
		} catch (IOException e) {
			e.printStackTrace();
			l = null;
		}
		return l;
	}

	/**
	 * figure out a string representing the relative path of 'f' with respect to
	 * 'r'
	 * 
	 * @param r
	 *            home path
	 * @param f
	 *            path of file
	 */
	private static String matchPathLists(List r, List f, char separator ) {
		int i;
		int j;
		StringBuffer s = new StringBuffer();
		// start at the beginning of the lists
		// iterate while both lists are equal
		i = r.size() - 1;
		j = f.size() - 1;

		// first eliminate common root
		while ((i >= 0) && (j >= 0) && (r.get(i).equals(f.get(j)))) {
			i--;
			j--;
		}

		// for each remaining level in the home path, add a ..
		for (; i >= 0; i--) {
			s.append( ".." ).append( separator );
		}

		// for each level in the file path, add the path
		for (; j >= 1; j--) {
			s.append( f.get(j) ).append( separator );
		}

		if ( s.length() == 0 )
			s.append( "./" );
		if ( j > -1 ) 
			s.append( f.get(j) ); // file name
		return s.toString();
	}

	/**
	 * get relative path of File 'f' with respect to 'home' directory example :
	 * home = /a/b/c f = /a/d/e/x.txt s = getRelativePath(home,f) =
	 * ../../d/e/x.txt
	 * 
	 * @author David M. Howard (from http://www.devx.com/tips/Tip/13737)
	 * @param home
	 *            base path, should be a directory, not a file, or it doesn't
	 *            make sense
	 * @param f
	 *            file to generate path for
	 * @return path from home to f as a string
	 */
	private static String getRelativePath(File home, File f, char separator ) {

		final List homelist = getPathList(home);
		final List filelist = getPathList(f);
		final String s = matchPathLists(homelist, filelist, separator );

		return s;
	}

	private static String getRelativePath(String home, String f, char separator) {
		return getRelativePath( new File(home), new File(f), separator );
	}
}